

import static any.Any.create;
import static any.functor.Functions.asMap;
import static any.functor.Functions.asNumber;
import static any.functor.Predicates.isNative;
import static any.functor.Predicates.canBeNumber;
import static any.functor.Predicates.canBeString;
import static any.impl.util.MapEntry.createMapEntry;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.StringReader;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

import org.jvyaml.YAML;

import antlr.RecognitionException;
import antlr.TokenStreamException;
import any.Any;
import any.ImmutableAny;
import any.incubator.ObjectHandlingStrategy;
import any.util.Any2JSON;
import any.util.AnyPrinter;

import com.sdicons.json.model.JSONValue;
import com.sdicons.json.parser.JSONParser;

public class AnyExamples {

	private static final AnyPrinter ANY_PRINTER = new AnyPrinter() {{
		indent = 3;
		linebreak = true;
		fullString = false;
	}};

	public static void main(String[] args) throws Exception {
		createSimpleAnys();

		System.out.println();
		System.out.println("*********************************************************");
		System.out.println();

		Any complexAny = createComplexAny();
		
		System.out.println();
		System.out.println("*********************************************************");
		System.out.println();

		json();

		System.out.println();
		System.out.println("*********************************************************");
		System.out.println();
		
		importYamlAsAny();
		
		System.out.println();
		System.out.println("*********************************************************");
		System.out.println();
		
		serialization(complexAny);
		
		System.out.println();
		System.out.println("*********************************************************");
		System.out.println();

		mapAny();
	}

	private static void mapAny() {
		System.out.println("Map-Any:");
		System.out.println("--------");
		
		Any mapAny = create.any()
		                   .put("1", 12)
		                   .put("2", "121")
		                   .put("3", new Object[] { 1, 2, "blubb" })
		                   .put("4", "string")
		                   .put("5", null)
		                   .put("6", true);
		
		System.out.println("Any: " + mapAny);
		System.out.println("asMap: " + mapAny.give(asMap()));
		System.out.println("asMap (Number): " + mapAny.give(asMap().eachElement(asNumber()).select(canBeNumber())));
		System.out.println("asMap (Native Number): " + mapAny.give(asMap().eachElement(asNumber()).select(isNative().Number())));
		Map<String, String> stringMap = mapAny.give(asMap().select(canBeString()));
		System.out.println("asMap (String): " + stringMap);
	}

	private static void json() throws TokenStreamException, RecognitionException {
		System.out.println("Read/Write JSON:");
		System.out.println("----------------");
		String jsonString = "{ " +
					"\"bla\" : { " +
						"\"key\" : \"value\", " +
						"\"2222222\" : \"33333333\"" +
					"}, " +
					"\"null\" : null, " +
					"\"zahl\" : 123, " +
					"\"array\" : [ 1, 2.5, 10, \"blubb\" ] " +
				"}";
		System.out.println("JSON-String: " + jsonString);
		
		JSONParser jsonParser = new JSONParser(new StringReader(jsonString));
		JSONValue jsonValue = jsonParser.nextValue();

		
		System.out.println("JSON-Value: " + jsonValue);
		
		Object jsonStripped = jsonValue.strip();
		System.out.println("JSON-Stripped: " + jsonStripped);
		Any jsonAny = create.any(true, jsonStripped);
		System.out.println("JSON-Any: " +jsonAny);

		Any2JSON jsonPrinter = new Any2JSON() {{
			indent = 3;
			linebreak = true;
			mode = Mode.INDEX_AS_KEY;
			strategy = ObjectHandlingStrategy.OMIT_OBJECT;
		}};
		System.out.println("JSON-Printer (1):");
		jsonAny.accept(jsonPrinter);
		
		Any any = create.any().appendEach(1, "bla", true).put("test", 1.0);
		any.get(2).append(new Date());
		System.out.println("JSON-Printer (2):");
		any.accept(jsonPrinter);		
	}

	private static void createSimpleAnys() {
		System.out.println("Create simple Anys:");
		System.out.println("-------------------");

		Any simpleAny1 = create.any();
		System.out.println("simpleAny1: " + simpleAny1);

		ImmutableAny simpleAny2 = create.immutableAny();
		System.out.println("simpleAny2: " + simpleAny2);
		
		Any simpleAny3 = create.any("");
		System.out.println("simpleAny3: " + simpleAny3);
		
		Any simpleAny4 = create.any(true, new Object[] {1, 1.0, new Date(), "abc"});
		System.out.println("simpleAny4: " + simpleAny4);
		
		Any simpleAny5 = create.any().put("key1", "blubb").put("key2", 1).put("key3", true);
		System.out.println("simpleAny5: " + simpleAny5);
	}

	private static Any createComplexAny() {
		System.out.println("Create a complex Any:");
		System.out.println("---------------------");

		Any complexAny = 
			create.any()
		          .put("key1", 1)
		          .appendEach(null, new Date(), "blubb")
		          .put(createMapEntry("key2", RoundingMode.DOWN))
		          .append(create.any()
		        		  .append("abc")
		        		  .put("key3", 12)
		        		  .append(new Date(0)))
		          .append(create.any().put("test", "blubb"))
		          .append(create.any(createMapEntry("key4", new SimpleDateFormat())))
		          ;
		
		System.out.println(ANY_PRINTER.toString(complexAny));
		
		return complexAny;
	}

	private static void importYamlAsAny() throws FileNotFoundException {
		Object yaml = YAML.load(new FileReader("test.yaml"));
		System.out.println("Parsed YAML: " + yaml);
		System.out.println("Parsed YAML type: " + yaml.getClass());
		
		Any yamlAny = create.any(yaml);
		
		System.out.println(ANY_PRINTER.toString(yamlAny));
	}

	private static void serialization(Any complexAny) throws Exception {
		System.out.println("Serializable-Type:");
		System.out.println("------------------");
		// We need something that implements Serializable
		ImmutableAny serial = create.any(new RuntimeException());
		System.out.println(serial.getType());
		System.out.println(serial.toFullString());
		System.out.println();
		
		System.out.println("(De-)serialize complex Any:");
		System.out.println("---------------------------");
		ObjectOutput objectOut = new ObjectOutputStream(new FileOutputStream("any.ser"));
		objectOut.writeObject("Any");
		objectOut.writeObject(complexAny);
		objectOut.flush();
		objectOut.close();

		ObjectInput objectIn = new ObjectInputStream(new FileInputStream("any.ser"));
		System.out.println(objectIn.readObject());
		Object readAny = objectIn.readObject();
		System.out.println(readAny);
		objectIn.close();

		System.out.println("Serialization worked: " + readAny.equals(complexAny));
	}

}
